package com.zrx.govern.component.easyexcel.starter.validate;

import com.zrx.govern.component.easyexcel.starter.entity.FieldRule;
import com.zrx.govern.component.easyexcel.starter.enums.DataTypeEnum;
import com.zrx.govern.component.easyexcel.starter.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.zrx.govern.component.easyexcel.starter.enums.ValidEnum.NON_NULL_CHECK;


/**
 * Excel校验器
 *
 * @author zhangxiaowei
 */
@Component
public class ExcelValidator {

    @Autowired
    private DicAccessor dicAccessor;

    private Map<String, Map<String, List<String>>> dicMap = new HashMap<>();

    private final String INTEGER_REG = "[0-9]*";

    private final String DECIMAL_REG = "^[+]?([0-9]+(.[0-9]{1,2})?)$";

    /**
     * 通用校验
     *
     * @param rules   约束
     * @param dataMap
     * @return
     */
    public String validate(Map<Integer, List<FieldRule>> rules, Map<Integer, Object> dataMap, String model) {
        HashSet<String> set = new HashSet<>();
        StringBuffer errorMsg = new StringBuffer();
        for (Integer index : rules.keySet()) {
            List<FieldRule> fieldRules = rules.get(index);
            fieldRules.forEach(fieldRule -> {
                try {
                    /*校验是否合法*/
                    if (invalidByRule(fieldRule, dataMap.get(index), model)) {
                        set.add(fieldRule.getMsg());
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
        for (String msg : set) {
            errorMsg.append(msg).append(";");
        }
        return errorMsg.toString();
    }

    /**
     * 根据不同类型进行校验，非法返回true
     * @param fieldRule
     * @param obj
     * @param model
     * @return
     * @throws ParseException
     */
    private boolean invalidByRule(FieldRule fieldRule, Object obj, String model) throws ParseException {
        String cellData = Objects.nonNull(obj) ? obj.toString() : "";
        /*不为非空校验且celldata为空*/
        if (fieldRule.getType() != NON_NULL_CHECK && StringUtils.isBlank(cellData)) {
            return false;
        }
        switch (fieldRule.getType()) {
            case NON_NULL_CHECK:
                return Objects.isNull(obj);
            case LENGTH_CHECK:
                if (Objects.isNull(fieldRule.getMaxLength()) || Objects.isNull(fieldRule.getMinLength())) {
                    throw new RuntimeException("模板json文件maxLength/minLength未定义");
                }
                return cellData.length() > fieldRule.getMaxLength() || cellData.length() < fieldRule.getMinLength();
            case REGEXP_CHECK:
                List<String> ruleVal = fieldRule.getVal();
                if (Objects.isNull(ruleVal) || ruleVal.isEmpty()) {
                    throw new RuntimeException("模板json文件正则表达公式未定义");
                }
                List<String> collect = ruleVal.stream().filter(val -> !Pattern.compile(val).matcher(cellData).matches()).collect(Collectors.toList());
                return collect.size() == ruleVal.size();
            case DATEFORMAT_CHECK:
                if (Objects.isNull(fieldRule.getDateVal())) {
                    throw new RuntimeException("模板json文件日期格式未定义");
                }
                return !DateUtil.isDateFormat(cellData) || !DateUtil.isVaild(cellData, fieldRule.getDateVal()) || Objects.nonNull(fieldRule.getMaxDay()) && !DateUtil.vaildMax(cellData,
                        fieldRule.getDateVal());
            case NUMERICAL:
                String dataType = fieldRule.getNumType();
                if (Objects.isNull(fieldRule.getNumType())) {
                    throw new RuntimeException("模板json文件数值类型未定义");
                }
                Matcher matcher = null;
                if (dataType.equals(DataTypeEnum.DECIMAL.getDataType())) {
                    matcher = Pattern.compile(DECIMAL_REG).matcher(cellData);
                }
                if (dataType.equals(DataTypeEnum.INTEGER.getDataType())) {
                    matcher = Pattern.compile(INTEGER_REG).matcher(cellData);
                }
                if (!Objects.isNull(matcher) && !matcher.matches()) {
                    return true;
                }
                BigDecimal data = new BigDecimal(cellData);
                BigDecimal min = new BigDecimal(fieldRule.getMin());
                BigDecimal max = new BigDecimal(fieldRule.getMax());
                return data.compareTo(min) < 0 || data.compareTo(max) > 0 || data.compareTo(max) == 0;
            case DICTIONARY_CHECK:
                if (Objects.isNull(dicMap.get(model))) {
                    Map<String, List<String>> map = dicAccessor.transferDictValue(model);
                    dicMap.put(model, map);
                }

                List<String> dicList = dicMap.get(model).get(fieldRule.getCode());
                if (dicList.isEmpty()) {
                    throw new RuntimeException("字典值未找到");
                }
                return !dicList.contains(cellData);
            default:
                break;
        }
        return false;
    }


}
